package com.sumer.psychology.blog.domain.model;

import com.sumer.psychology.common.Assert;
import com.sumer.psychology.common.BusinessException;
import com.sumer.psychology.common.domain.model.Author;
import com.sumer.psychology.common.domain.model.ConcurrencySafeEntity;
import com.sumer.psychology.tag.domain.model.AbstractTaggedEntity;
import com.sumer.psychology.tag.domain.model.Tag;
import com.sumer.psychology.tag.domain.model.TagDomainRegistry;
import org.apache.commons.lang3.StringEscapeUtils;

import java.util.Date;
import java.util.Set;

/**
 * a Blog
 * <p/>
 * Created by zhu on 14-8-10.
 */
public class Blog extends ConcurrencySafeEntity {
    private BlogId blogId;
    private BlogAvailability availability;
    private String title;
    private String content;
    private Date createTime;
    private Date lastModifyTime;
    private Author author;
    private Boolean recommended;

    private Category category;

    public Blog() {
    }

    /**
     * 创建Blog
     *
     * @param identity id
     * @param author   author
     * @param title    title
     * @param content  content
     */
    public Blog(BlogId identity, Author author, String title, String content) {
        initializeBlog(identity, author, title, content);

        apply(new BlogCreatedEvent(
                blogId(),
                title(),
                content(),
                author()));
    }

    /**
     * 创建带有分类的Blog
     *
     * @param identity  id
     * @param author    author
     * @param title     title
     * @param content   content
     * @param aCategory category
     */
    public Blog(BlogId identity, Author author, String title, String content, Category aCategory) {
        if (aCategory == null) {
            throw new BusinessException("目录不能为空");
        }
        initializeBlog(identity, author, title, content);
        setCategory(aCategory);

        apply(new BlogCreatedEvent(
                blogId(),
                title(),
                content(),
                author(),
                aCategory.categoryId().identity()));
    }

    /**
     * 初始化Blog
     *
     * @param identity id
     * @param author   author
     * @param title    title
     * @param content  content
     */
    private void initializeBlog(BlogId identity, Author author, String title, String content) {
        setBlogId(identity);
        setAuthor(author);
        setTitle(title);
        setContent(content);
        setAvailability(BlogAvailability.ACTIVE);
        setCreateTime(new Date());
    }

    /**
     * 放入回收站
     */
    public void recycleBin() {
        setAvailability(BlogAvailability.DEACTIVE);
        setLastModifyTime(new Date());

        apply(new BlogPutToRecycleBinEvent(blogId()));
    }

    /**
     * 从回收站恢复
     */
    public void restore() {
        if (availability() == BlogAvailability.DEACTIVE) {
            setAvailability(BlogAvailability.ACTIVE);

            apply(new BlogRestoredEvent(
                    blogId(),
                    title(),
                    author()));
        }
    }

    /**
     * 完全删除
     */
    public void deleteCompletely() {
        setAvailability(BlogAvailability.DELETED);
        setLastModifyTime(new Date());

        apply(new BlogDeletedEvent(blogId()));
    }

    /**
     * 修改Blog
     *
     * @param title   title
     * @param content content
     */
    public void change(String title, String content) {
        if (title().equals(title) && content().equals(content)) {
            return;
        }

        setTitle(title);
        setContent(content);
        setLastModifyTime(new Date());

        apply(new BlogChangedEvent(
                blogId(),
                title(),
                content(),
                author()));
    }

    /**
     * Blog归类
     *
     * @param aCategory category
     */
    public void categorizeInto(Category aCategory) {
        if (aCategory == null) {
            throw new BusinessException("目录不存在");
        }
        if (category() != null && aCategory.categoryId().equals(category().categoryId())) {
            return;
        }

        setCategory(aCategory);
        setLastModifyTime(new Date());

        apply(new BlogClassifiedEvent(
                blogId(),
                category().categoryId().identity(),
                author()));
    }

    /**
     * 去除分类
     */
    public void removeCategory() {
        setCategory(null);
        setLastModifyTime(new Date());

        apply(new BlogCategoryRemovedEvent(blogId()));
    }

    /**
     * 设置为精华帖
     */
    public void recommend() {
        if (!recommended()) {
            this.recommended = true;
            setLastModifyTime(new Date());

            apply(new BlogRecommendedEvent(blogId()));
        }
    }

    /**
     * 删除精华标志
     */
    public void cancelRecommendation() {
        if (recommended()) {
            this.recommended = false;
            setLastModifyTime(new Date());

            apply(new BlogRecommendationCaneled(blogId()));
        }
    }

    public Date createTime() {
        return this.createTime;
    }

    public String title() {
        return this.title;
    }

    public String content() {
        return this.content;
    }

    public Author author() {
        return this.author;
    }

    public BlogAvailability availability() {
        return this.availability;
    }

    public BlogId blogId() {
        return this.blogId;
    }

    public Date lastModifyTime() {
        return lastModifyTime;
    }

    public Category category() {
        return category;
    }

    public Boolean recommended() {
        return recommended == null ? false : recommended;
    }

    private void setAvailability(BlogAvailability availability) {
        Assert.notNull(availability, "Blog状态不能为空");
        this.availability = availability;
    }

    private void setTitle(String title) {
        Assert.notEmpty(title, "Blog标题不能为空");
        this.title = title;
    }

    private void setContent(String content) {
        Assert.notEmpty(content, "Blog内容不能为空");
        this.content = StringEscapeUtils.escapeHtml4(content);
    }

    private void setCreateTime(Date createTime) {
        Assert.notNull(createTime, "Blog创建时间不能为空");
        this.createTime = createTime;
    }

    private void setAuthor(Author author) {
        Assert.notNull(author, "Blog作者不能为空");
        this.author = author;
    }

    private void setBlogId(BlogId identity) {
        Assert.notNull(identity, "Blog唯一标识不能为空");
        this.blogId = identity;
    }

    private void setLastModifyTime(Date lastModifyTime) {
        this.lastModifyTime = lastModifyTime;
    }

    private void setCategory(Category category) {
        if (category != null) {
            Assert.notNull(category.categoryId(), "目录id不能为空");
            Assert.notEmpty(category.categoryId().identity(), "目录id不能为空");
            Assert.isTrue(category.active(), "目录状态未激活");
        }
        this.category = category;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Blog blog = (Blog) o;

        if (recommended() != blog.recommended()) return false;
        if (author != null ? !author.equals(blog.author) : blog.author != null) return false;
        if (availability != blog.availability) return false;
        if (blogId != null ? !blogId.equals(blog.blogId) : blog.blogId != null) return false;
        if (category != null ? !category.equals(blog.category) : blog.category != null) return false;
        if (content != null ? !content.equals(blog.content) : blog.content != null) return false;
        if (title != null ? !title.equals(blog.title) : blog.title != null) return false;

        return true;
    }

    @Override
    public int hashCode() {
        int result = blogId != null ? blogId.hashCode() : 0;
        result = 31 * result + (availability != null ? availability.hashCode() : 0);
        result = 31 * result + (title != null ? title.hashCode() : 0);
        result = 31 * result + (content != null ? content.hashCode() : 0);
        result = 31 * result + (author != null ? author.hashCode() : 0);
        result = 31 * result + (recommended() ? 1 : 0);
        result = 31 * result + (category != null ? category.hashCode() : 0);
        return result;
    }

    @Override
    public String toString() {
        return "Blog{" +
                "blogId=" + blogId +
                ", availability=" + availability +
                ", title='" + title + '\'' +
                ", content='" + content + '\'' +
                ", createTime=" + createTime +
                ", lastModifyTime=" + lastModifyTime +
                ", author=" + author +
                ", best=" + recommended() +
                ", category=" + category +
                '}';
    }

}
